package com.xs.valid.demo.aop;

import com.xs.valid.demo.annotation.JsonBeanAnnotation;
import com.xs.valid.demo.common.RestEnum;
import com.xs.valid.demo.common.ResultUtils;
import com.xs.valid.demo.utils.JacksonUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.List;

/**
 * @author xs
 * date 2017/11/28 10:04
 */
@Aspect
@Component
public class MyAspect {
    //使用org.slf4j.Logger,这是Spring实现日志的方法
    private final static Logger logger = LoggerFactory.getLogger(MyAspect.class);

    /**
     * 定义AOP扫描路径
     */
    @Pointcut("execution(* com.xs.valid.demo.web.*.*(..)) ")
    public void log() {
    }


    /**
     * 环绕通知：
     * 环绕通知非常强大，可以决定目标方法是否执行，什么时候执行，执行时是否需要替换方法参数，执行完毕是否需要替换返回值。
     * 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型
     */
    @Around("log()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("before------->");
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Annotation[][] methodAnnotations = method.getParameterAnnotations();
        Object[] args = joinPoint.getArgs();
        for (int j = 0; j < methodAnnotations.length; j++) {
            int length = methodAnnotations[j].length;{
                for (int k = 0; k < length; k++) {
                    if (methodAnnotations[j][k].annotationType().equals(Class.forName("javax.validation.Valid"))) {
                        //如果controller 方法包含Valid 注解
                        System.out.println("方法包含Valid 注解  ");
                        BindingResult bindingResult = (BindingResult) args[k + 1];
                        if (bindingResult.hasErrors()) {
                            String firstErrorMsg=bindingResult.getFieldErrors().stream().findFirst().get().getDefaultMessage();
                            return ResultUtils.error(RestEnum.PARAMETER_INVALID,firstErrorMsg);
                        }
                    }
                }
            }
        }
        Object objectResult = joinPoint.proceed();    //正常运行
        return objectResult;
    }


    @Around(value = "execution(* com.xs.valid.demo.web.*.*(..)) && @annotation(jsonBeanAnnotation)")
    public Object aroundMethod(ProceedingJoinPoint pjd, JsonBeanAnnotation jsonBeanAnnotation) throws Exception {
        Object result = null;
        System.out.println(jsonBeanAnnotation.classType());
        Object[] args = pjd.getArgs();
//        if(args.length!=2){
//            throw  new Exception("参数个数越界，只能包含两个参数");
//        }
        for (Object arg : args) {
            if(jsonBeanAnnotation.isJsonArry()){
                if(arg instanceof String){
                    List<?> objects = JacksonUtil.jsonArray2PojoList(arg.toString(), Class.forName(jsonBeanAnnotation.classType().trim()));
                }

            }
        }
        try {
            System.out.println("前置通知");
            result = pjd.proceed();
            System.out.println("后置通知");
        } catch (Throwable e) {
            System.out.println("异常通知");
        }
        System.out.println("返回通知");
        return result;
    }
}
